package com.bah.tract.client.workstore;

import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.BeanUtils;

import com.bah.tract.client.ErrorHandler;
import com.bah.tract.client.WorkLog;
import com.bah.tract.mapping.PropertyHelper;
import com.bah.tract.service.Task;
import com.bah.tract.service.Work;

public abstract class WorkStore<T extends Effort> {

	private static final int MILLISECONDS_PER_MINUTE = 60000;
	private final WorkLog mWorkLog;
	private final String mTaskType;

	protected WorkStore(final WorkLog workLog, final String taskType) {
		mWorkLog = workLog;
		mTaskType = taskType;
	}

	public final Set<T> getWork() {
		final Map<T, T> allWork = new HashMap<T, T>();
		final Date today = new Date();
		// Find all work that includes a task of the provided type
		for (final Work work : mWorkLog.getDaysWork(today)) {
			for (final Task task : work.getTasks()) {
				if (mTaskType.equals(task.getType())) {
					final Map<String, Object> properties = new HashMap<String, Object>();
					PropertyHelper.processProperties(properties,
							task.getIdentifyingProperty());
					PropertyHelper.processProperties(properties,
							task.getDescriptiveProperty());
					final T t = makeWork();
					try {
						BeanUtils.populate(t, properties);
						BeanUtils.copyProperties(t, task);
						final long effort = work.getEnd().toGregorianCalendar()
								.getTimeInMillis()
								- work.getStart().toGregorianCalendar()
										.getTimeInMillis();

						t.setMinutes(effort / MILLISECONDS_PER_MINUTE);
						if (allWork.containsKey(t)) {
							// We already have this task add the effort
							final T oldWork = allWork.get(t);
							oldWork.setMinutes(oldWork.getMinutes()
									+ t.getMinutes());
						} else {
							allWork.put(t, t);
						}
					} catch (final IllegalAccessException e) {
						ErrorHandler.handleError(e);
					} catch (final InvocationTargetException e) {
						ErrorHandler.handleError(e);
					}
				}
			}
		}
		final Set<T> totaledWork = allWork.keySet();
		processWork(totaledWork);
		return totaledWork;
	}

	protected void processWork(final Set<T> totaledWork) {
	}

	protected abstract T makeWork();
}
